﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

namespace BambooGenTool.Helper
{
    public class GenerateUtil
    {
        public string GetNextWord(string input, int startPosition)
        {
            int endPosition = input.Length;
            for (int i = startPosition + 1; i < input.Length; i++)
            {
                if (char.IsUpper(input[i]))
                {
                    endPosition = i;
                    break;
                }
            }
            return input.Substring(startPosition, endPosition - startPosition);
        }
        public IList<string> GetWordsFromName(string name)
        {
            int startPosition = 0;
            string word = "";
            IList<string> wordList = new List<string>();
            while (startPosition < name.Length)
            {
                word = this.GetNextWord(name, startPosition);
                wordList.Add(word);
                startPosition += word.Length;
            }
            return wordList;
        }
        public string GetSQLColumnType(PropertyInfo property)
        {
            string typeName = property.PropertyType.Name.ToLower();
            typeName = ConvertToBasicType(property.PropertyType);
            string output = "";
            if (typeName == "string")
            {
                if (property.Name.IndexOf("Name") >= 0)
                {
                    output = "sql-type=\"nvarchar(200)\"";
                }
                else if (property.Name.IndexOf("Email") >= 0)
                {
                    output = "sql-type=\"varchar(200)\"";
                }
                else 
                {
                    output = "sql-type=\"varchar(200)\"";
                }
            }
            else if (typeName == "bool" || typeName == "boolean")
            {
                output = "";
            }
            return output;
        }
        public string GetDatabaseColumn(PropertyInfo property)
        {
            string propertyName = property.Name;
            string columnName = "col";
            IList<string> words = GetWordsFromName(propertyName);
            foreach (string word in words)
            {
                columnName += "_" + word.ToLower();
            }
            return columnName;
        }
        public IList<Type> GetAllTypesOfNameSpace(string nameSpace, string dllPath)
        {
            Assembly assembly = Assembly.LoadFrom(dllPath);
            Type[] allClassesInAssembly = assembly.GetTypes();
            IList<Type> entityClassList = new List<Type>();
            if (allClassesInAssembly == null)
            {
                return entityClassList;
            }
            foreach (Type type in allClassesInAssembly)
            {
                if (type.Namespace == nameSpace && IsEntityType(type))
                {
                    entityClassList.Add(type);
                }
            }
            return entityClassList;
        }

        public bool IsEntityType(Type type)
        {
            PropertyInfo[] propertyListOfEntity = type.GetProperties();
            if (propertyListOfEntity == null)
            {
                return false;
            }
            foreach (PropertyInfo property in propertyListOfEntity)
            {
                if (property.Name == "ID")
                {
                    return true;
                }
            }
            return false;
        }


        public bool IsBasicProperty(PropertyInfo property)
        {
            return IsBasicType(property.PropertyType);
        }

        public bool IsObjectProperty(PropertyInfo property)
        {
            return IsObjectType(property.PropertyType);
        }

        public bool IsBasicType(Type type)
        {
            if (type.IsPrimitive)
            {
                return type.IsPrimitive;
            }
            string typeNameLower = type.Name.ToLower();
            if (typeNameLower.EndsWith("string") ||
                typeNameLower.EndsWith("float") ||
                typeNameLower.EndsWith("boolean") ||
                typeNameLower.EndsWith("int") ||
                typeNameLower.EndsWith("char") ||
                typeNameLower.EndsWith("double") ||
                typeNameLower.EndsWith("byte[]") ||
                typeNameLower.EndsWith("[]byte")
                )
            {
                return true;
            }
            return false;
        }

        public bool IsObjectType(Type type)
        {
            string typeNameLower = type.Name.ToLower();
            return (type.IsClass
                    && typeNameLower != "string"
                    && typeNameLower != "array"
                    && typeNameLower != "object"
                    && typeNameLower != "arraylist"
                    && typeNameLower != "list"
                    && typeNameLower != "float"
                    && typeNameLower != "double"
                    && typeNameLower != "int"
                    && typeNameLower != "char"
                    && typeNameLower != "integer");
        }

        public IList<PropertyInfo> GetAllMemberProperty(Type type)
        {
            IList<PropertyInfo> memberPropertyList = new List<PropertyInfo>();
            PropertyInfo[] properties = type.GetProperties();
            if (properties != null)
            {
                foreach (PropertyInfo property in properties)
                {
                    if (IsBasicProperty(property) ||
                        IsObjectProperty(property))
                    {
                        memberPropertyList.Add(property);
                    }
                }
            }
            return memberPropertyList;
        }

        public IList<PropertyInfo> GetAllObjectProperty(Type type)
        {
            IList<PropertyInfo> memberPropertyList = new List<PropertyInfo>();
            PropertyInfo[] properties = type.GetProperties();
            if (properties != null)
            {
                foreach (PropertyInfo property in properties)
                {
                    if (property.Name != "ID"
                        && IsObjectProperty(property))
                    {
                        memberPropertyList.Add(property);
                    }
                }
            }
            return memberPropertyList;
        }

        public IList<PropertyInfo> GetAllNonObjectProperty(Type type)
        {
            IList<PropertyInfo> memberPropertyList = new List<PropertyInfo>();
            PropertyInfo[] properties = type.GetProperties();
            if (properties != null)
            {
                foreach (PropertyInfo property in properties)
                {
                    if (property.Name != "ID"
                        && !IsObjectProperty(property))
                    {
                        memberPropertyList.Add(property);
                    }
                }
            }
            return memberPropertyList;
        }


        public IList<PropertyInfo> GetAllNonPrimaryKeyProperty(Type type)
        {
            IList<PropertyInfo> memberPropertyList = new List<PropertyInfo>();
            PropertyInfo[] properties = type.GetProperties();
            if (properties != null)
            {
                foreach (PropertyInfo property in properties)
                {
                    if (property.Name != "ID" &&
                        (IsBasicProperty(property)
                            || IsObjectProperty(property)))
                    {
                        memberPropertyList.Add(property);
                    }
                }
            }
            return memberPropertyList;
        }

        public PropertyInfo GetPrimaryKeyProperty(Type type)
        {
            PropertyInfo[] properties = type.GetProperties();
            PropertyInfo keyProperty = null;
            if (properties != null)
            {
                foreach (PropertyInfo property in properties)
                {
                    if (property.Name == "ID")
                    {
                        keyProperty = property;
                        break;
                    }
                }
            }
            return keyProperty;
        }

        public string GetCSharpType(string databaseTypeName)
        {
            string normalDBTypeName = databaseTypeName.Trim().ToLower();
            string csharpType = "";
            if (normalDBTypeName == "int")
            {
                csharpType = "int";
            }
            else if (normalDBTypeName == "bigint")
            {
                csharpType = "long";
            }
            else if (normalDBTypeName == "real")
            {
                csharpType = "float";
            }
            else if (normalDBTypeName == "numeric" || normalDBTypeName.Contains("numeric"))
            {
                csharpType = "float";
            }
            else if (normalDBTypeName == "datetime")
            {
                csharpType = "DateTime";
            }
            else if (normalDBTypeName == "smalldatetime")
            {
                csharpType = "DateTime";
            }
            else if (normalDBTypeName == "smallint")
            {
                csharpType = "byte";
            }
            else if (normalDBTypeName == "tinyint")
            {
                csharpType = "int";
            }
            else if (normalDBTypeName == "bit")
            {
                csharpType = "bool";
            }
            else if (normalDBTypeName.Contains("varchar"))
            {
                csharpType = "string";
            }
            else if (normalDBTypeName.Contains("char"))
            {
                csharpType = "string";
            }
            else if (normalDBTypeName.Contains("text"))
            {
                csharpType = "string";
            }

            return csharpType;

        }
        public string ConvertToBasicType(Type type)
        {
            string outputType = type.Name;
            string typeNameLower = type.Name.ToLower();
            if (typeNameLower == "ilist" || type.FullName.ToLower().Contains("ilist"))
            {
                outputType = "IList";
                return outputType;
            } 
            else 
            if (typeNameLower == "uint16" || type.FullName.ToLower().Contains("uint16"))
            {
                outputType = type.IsGenericType ? "ushort?" : "ushort";
                return outputType;
            }
            else  if (typeNameLower == "int16" || type.FullName.ToLower().Contains("int16"))
            {
                outputType = type.IsGenericType ? "short?" : "short";
                return outputType;
            }
            else if (typeNameLower == "uint32" || type.FullName.ToLower().Contains("uint32"))
            {
                outputType = type.IsGenericType ? "uint?" : "uint";
                return outputType;
            }
            else if (typeNameLower == "int32" || type.FullName.ToLower().Contains("int32"))
            {
                outputType = type.IsGenericType ? "int?" : "int";
                return outputType;
            }
            else if (typeNameLower == "uint64" || type.FullName.ToLower().Contains("uint64"))
            {
                outputType = type.IsGenericType ? "ulong?" : "ulong";
                return outputType;
            }
            else if (typeNameLower == "int64" || type.FullName.ToLower().Contains("int64"))
            {
                outputType = type.IsGenericType ? "long?" : "long";
                return outputType;
            }
            else if (typeNameLower == "sbyte" || type.FullName.ToLower().Contains("sbyte"))
            {
                outputType = type.IsGenericType ? "sbyte?" : "sbyte";
                return outputType;
            }
            else if (typeNameLower == "byte" || type.FullName.ToLower().Contains("byte"))
            {
                outputType = type.IsGenericType ? "byte?" : "byte";
                return outputType;
            }
            
            
            else if (typeNameLower == "single" || type.FullName.ToLower().Contains("single"))
            {
                outputType = type.IsGenericType ? "float?" : "float";
                return outputType;
            }
            else if (typeNameLower == "boolean" || type.FullName.ToLower().Contains("boolean"))
            {
                outputType = type.IsGenericType ? "bool?" : "bool";
                return outputType;
            }
            else if (typeNameLower == "string")
            {
                outputType = "string";
                return outputType;
            }
            else if (typeNameLower == "char" || type.FullName.ToLower().Contains("char"))
            {
                outputType = type.IsGenericType ? "char?" : "char";
                return outputType;
            }
            else if (typeNameLower == "decimal" || type.FullName.ToLower().Contains("decimal"))
            {
                outputType = type.IsGenericType ? "decimal?" : "decimal";
                return outputType;
            }
            else if (typeNameLower == "double" || type.FullName.ToLower().Contains("double"))
            {
                outputType = type.IsGenericType ? "double?" : "double";
                return outputType;
            }
            else if (type.FullName.Contains("DateTime"))
            {
                outputType = type.IsGenericType ? "DateTime?" : "DateTime";
                return outputType;
            }
            
            return outputType;
        }

        public string SetPascalCase(string name)
        {
            string buff = "";
            bool next2upper = true;
            bool allUpper = true;

            // checks for names in all CAPS
            foreach (char c in name)
            {
                if (Char.IsLower(c))
                {
                    allUpper = false;
                    break;
                }
            }

            foreach (char c in name)
            {
                switch (c)
                {
                    // Trim spaces
                    case ' ':
                        next2upper = true;
                        break;
                    // Trim underscores
                    case '_':
                        next2upper = true;
                        break;
                    // Trim periods
                    case '.':
                        next2upper = true;
                        break;
                    default:
                        if (next2upper)
                        {
                            buff += c.ToString().ToUpper();
                            next2upper = false;
                        }
                        else if (allUpper)
                        {
                            buff += c.ToString().ToLower();
                        }
                        else
                        {
                            buff += c.ToString();
                        }
                        break;
                }
            }

            return buff;
        }


        public string SetCamelCase(string name)
        {
            string buff = "";
            bool next2upper = false;
            bool firstLetter = true;
            bool allUpper = true;

            // checks for names in all CAPS
            foreach (char c in name)
            {
                if (Char.IsLower(c))
                {
                    allUpper = false;
                    break;
                }
            }

            foreach (char c in name)
            {
                switch (c)
                {
                    // Trim spaces
                    case ' ':
                        if (!firstLetter)
                        {
                            next2upper = true;
                        }
                        break;
                    // Trim underscores
                    case '_':
                        if (!firstLetter)
                        {
                            next2upper = true;
                        }
                        break;
                    // Trim periods
                    case '.':
                        if (!firstLetter)
                        {
                            next2upper = true;
                        }
                        break;
                    default:
                        if (next2upper)
                        {
                            buff += c.ToString().ToUpper();
                            next2upper = false;
                        }
                        else
                        {
                            if (firstLetter)
                            {
                                buff += c.ToString().ToLower();
                                firstLetter = false;
                            }
                            else if (allUpper)
                            {
                                buff += c.ToString().ToLower();
                            }
                            else
                            {
                                buff += c.ToString();
                            }
                        }

                        break;
                }
            }

            return buff;
        }
    }
}
